/*
 * Copyright (C) 2009 Georgios J. Georgopoulos, All rights reserved.
 * 
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 * 
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
 * site: http://www.fsf.org.
 */
package org.gwt.mosaic.xul.client.ui;

import org.gwt.beansbinding.core.client.Binding;
import org.gwt.beansbinding.core.client.PropertyStateEvent;
import org.gwt.beansbinding.core.client.PropertyStateListener;
import org.gwt.mosaic.actions.client.Action;
import org.gwt.mosaic.actions.client.ActionMap;
import org.gwt.mosaic.actions.client.CheckBoxBindings;
import org.gwt.mosaic.application.client.Application;
import org.gwt.mosaic.core.client.DOM;

import com.google.gwt.user.client.ui.Widget;

/**
 * An element that can be turned on and off. This is most commonly rendered as a
 * box when the element is off and a box with a check when the element is on.
 * The user can switch the state of the check box by selecting it with the
 * mouse. A label, specified with the label attribute, may be added beside the
 * check box.
 * 
 * @author georgopoulos.georgios(at)gmail.com
 * 
 */
public class Checkbox extends Element {
  private static final long serialVersionUID = 6698727448246190231L;

  private transient com.google.gwt.user.client.ui.CheckBox checkBox = null;

  // -----------------------------------------------------------------------
  /**
   * Indicates whether the element is checked or not.
   */
  public static final String CHECKED = "checked";

  public boolean isChecked() {
    return getBoolean(CHECKED);
  }

  public void setChecked(boolean checked) {
    putBoolean(CHECKED, checked);
  }

  // -----------------------------------------------------------------------
  /**
   * Set to the id of a command element that is being observed by the element.
   */
  public static final String COMMAND = "command";

  public String getCommand() {
    return getString(COMMAND);
  }

  public void setCommand(String command) {
    putString(COMMAND, command);
  }

  // -----------------------------------------------------------------------
  /**
   * Indicates whether the element is disabled or not. If this element is set to
   * true the element is disabled. Disabled elements are usually drawn with
   * grayed-out text. If the element is disabled, it does not respond to user
   * actions, it cannot be focused, and the command event will not fire.
   */
  public static final String DISABLED = "disabled";

  public boolean isDisabled() {
    return getBoolean(DISABLED);
  }

  public void setDisabled(boolean disabled) {
    putBoolean(DISABLED, disabled);
  }

  // -----------------------------------------------------------------------
  /**
   * The label that will appear on the element. If this is left out, no text
   * appears.
   */
  public static final String LABEL = "label";

  public String getLabel() {
    return getString(LABEL);
  }

  public void setLabel(String label) {
    putString(LABEL, label);
  }

  // -----------------------------------------------------------------------
  private transient CheckBoxBindings checkBoxBindings = null;

  // -----------------------------------------------------------------------
  @Override
  protected Widget createUI() {
    if (checkBox == null) {
      checkBox = new com.google.gwt.user.client.ui.CheckBox();
      DOM.setStyleAttribute(checkBox.getElement(), "whiteSpace", "nowrap");
    }

    syncUI(checkBox);

    return checkBox;
  }

  // -----------------------------------------------------------------------
  @SuppressWarnings("unchecked")
  @Override
  protected void syncUI(Widget ui) {
    super.syncUI(ui);
    
    checkBox.setValue(isChecked());
    
    if (attributeMap.containsKey(LABEL)) {
      checkBox.setText(getLabel());
    }
    
    checkBox.setEnabled(!isDisabled());

    if (checkBoxBindings != null) {
      checkBoxBindings.unbind();
      checkBoxBindings = null;
    }

    String command = getCommand();
    if (command != null) {
      final ActionMap actionMap = Application.getInstance().getContext().getActionMap();
      final Action action = actionMap.get(getCommand());
      if (action != null) {
        checkBoxBindings = new CheckBoxBindings(action, checkBox);

        Binding nameBinding = checkBoxBindings.getBinding(Action.NAME);
        nameBinding.setSourceNullValue(getLabel());
        nameBinding.getTargetProperty().addPropertyStateListener(
            nameBinding.getTargetObject(), new PropertyStateListener() {
              public void propertyStateChanged(PropertyStateEvent pse) {
                System.out.println("Name changed: " + pse.getNewValue());
                Checkbox.this.setLabel((String) pse.getNewValue());
              }
            });

        Binding shortDescrBinding = checkBoxBindings.getBinding(Action.SHORT_DESCRIPTION);
        shortDescrBinding.setSourceNullValue(getTooltiptext());
        shortDescrBinding.getTargetProperty().addPropertyStateListener(
            shortDescrBinding.getTargetObject(), new PropertyStateListener() {
              public void propertyStateChanged(PropertyStateEvent pse) {
                System.out.println("ShortDescription changed: "
                    + pse.getNewValue());
                Checkbox.this.setTooltiptext((String) pse.getNewValue());
              }
            });

        Binding enabledBinding = checkBoxBindings.getBinding("enabled");
        // enabledBinding.setSourceNullValue(.action......);
        enabledBinding.getTargetProperty().addPropertyStateListener(
            enabledBinding.getTargetObject(), new PropertyStateListener() {
              public void propertyStateChanged(PropertyStateEvent pse) {
                System.out.println("Enabled changed: " + pse.getNewValue());
                Checkbox.this.setDisabled(!((Boolean) pse.getNewValue()));
              }
            });

        Binding selectedBinding = checkBoxBindings.getBinding("selected");
        // selectedBinding.setSourceNullValue(.action......);
        selectedBinding.getTargetProperty().addPropertyStateListener(
            selectedBinding.getTargetObject(), new PropertyStateListener() {
              public void propertyStateChanged(PropertyStateEvent pse) {
                System.out.println("Selected changed: " + pse.getNewValue());
                Checkbox.this.setChecked((Boolean) pse.getNewValue());
              }
            });

        Binding visibleBinding = checkBoxBindings.getBinding("visible");
        // visibleBinding.setSourceNullValue(.action......);
        visibleBinding.getTargetProperty().addPropertyStateListener(
            visibleBinding.getTargetObject(), new PropertyStateListener() {
              public void propertyStateChanged(PropertyStateEvent pse) {
                System.out.println("Visible changed: " + pse.getNewValue());
                Checkbox.this.setHidden(!((Boolean) pse.getNewValue()));
              }
            });

        checkBoxBindings.bind();
      }

    }
  }
}
